#include "ibms_in.h"

int OnAcceptingSocket( struct IbmsEnv *p_env , struct ListenSession *p_listen_session )
{
	struct AcceptedSession	*p_accepted_session = NULL ;
	SOCKLEN_T		accept_addr_len ;
	
	struct epoll_event	event ;
	
	int			nret = 0 ;
	
	p_accepted_session = (struct AcceptedSession *)malloc( sizeof(struct AcceptedSession) ) ;
	if( p_accepted_session == NULL )
	{
		ERRORLOGSG( "malloc failed , errno[%d]" , errno );
		return 1;
	}
	memset( p_accepted_session , 0x00 , sizeof(struct AcceptedSession) );
	
	accept_addr_len = sizeof(struct sockaddr) ;
	p_accepted_session->netaddr.sock = accept( p_listen_session->netaddr.sock , (struct sockaddr *) & (p_accepted_session->netaddr.addr) , & accept_addr_len ) ;
	if( p_accepted_session->netaddr.sock == -1 )
	{
		ERRORLOGSG( "accept failed , errno[%d]" , errno );
		free( p_accepted_session );
		return 1;
	}
	
	SetHttpNonblock( p_accepted_session->netaddr.sock );
	SetHttpNodelay( p_accepted_session->netaddr.sock , 1 );
	SetHttpLinger( p_accepted_session->netaddr.sock , -1 );
	
	GETNETADDRESS( p_accepted_session->netaddr )
	GETNETADDRESS_REMOTE( p_accepted_session->netaddr )
	
	p_accepted_session->http = CreateHttpEnv() ;
	if( p_accepted_session->http == NULL )
	{
		ERRORLOGSG( "CreateHttpEnv failed , errno[%d]" , errno );
		close( p_accepted_session->netaddr.sock );
		free( p_accepted_session );
		return 1;
	}
	
	p_accepted_session->http_secure_env = CreateHttpSecureEnv( IBP_HTTPSECURE_SIGN_FLAG_MD5 , IBP_HTTPSECURE_COMPRESS_FLAG_GZIP , 0 ) ;
	if( p_accepted_session->http_secure_env == NULL )
	{
		ERRORLOGSG( "CreateHttpSecureEnv failed , errno[%d]" , errno );
		DestroyHttpEnv( p_accepted_session->http );
		close( p_accepted_session->netaddr.sock );
		free( p_accepted_session );
		return -1;
	}
	
	memset( & event , 0x00 , sizeof(struct epoll_event) );
	event.events = EPOLLIN | EPOLLERR ;
	event.data.ptr = p_accepted_session ;
	nret = epoll_ctl( p_env->epoll_fd , EPOLL_CTL_ADD , p_accepted_session->netaddr.sock , & event ) ;
	if( nret == -1 )
	{
		ERRORLOGSG( "epoll_ctl[%d] add[%d] failed , errno[%d]" , p_env->epoll_fd , p_accepted_session->netaddr.sock , errno );
		DestroyHttpSecureEnv( p_accepted_session->http_secure_env );
		DestroyHttpEnv( p_accepted_session->http );
		close( p_accepted_session->netaddr.sock );
		free( p_accepted_session );
		return 1;
	}
	else
	{
		DEBUGLOGSG( "epoll_ctl[%d] add[%d] ok" , p_env->epoll_fd , p_accepted_session->netaddr.sock );
	}
	
	p_accepted_session->role = ACCEPTEDSESSION_ROLE_UNKNOWN_IDENTITY ;
	
	list_add_tail( & (p_accepted_session->this_node) , & (p_env->accepted_session_list.this_node) );
	
	return 0;
}

void OnClosingSocket( struct IbmsEnv *p_env , struct AcceptedSession *p_accepted_session )
{
#if 0
	struct IbmsNode		*p_node = NULL ;
	struct IbmsNodeHost	*p_node_host = NULL ;
	
	int			nret = 0 ;
#endif
	
	if( p_accepted_session )
	{
#if 0
		if( p_accepted_session->role == ACCEPTEDSESSION_ROLE_IBAS )
		{
			p_node = QueryIbmsNodeTreeNode( p_env , & (p_accepted_session->node) ) ;
			if( p_node )
			{
				p_node_host = QueryIbmsNodeHostTreeNode( p_node , & (p_accepted_session->node_host) ) ;
				if( p_node_host )
				{
					p_node_host->alive_connections--;
					if( p_node_host->alive_connections == 0 )
						p_node_host->invalid = 1 ;
				}
			}
			
			p_accepted_session->node_host.invalid = 1 ;
			
			nret = NoticeNodesInvalid( p_env , p_accepted_session ) ;
			if( nret != HTTP_OK )
			{
				ERRORLOGSG( "NoticeNodesInvalid failed[%d]" , nret );
			}
			else
			{
				INFOLOGSG( "NoticeNodesInvalid ok" );
			}
		}
#endif
		
		INFOLOGSG( "close session[%s]" , p_accepted_session->node.node );
		DestroyHttpSecureEnv( p_accepted_session->http_secure_env );
		DestroyHttpEnv( p_accepted_session->http );
		epoll_ctl( p_env->epoll_fd , EPOLL_CTL_DEL , p_accepted_session->netaddr.sock , NULL );
		close( p_accepted_session->netaddr.sock );
		list_del( & (p_accepted_session->this_node) );
		free( p_accepted_session );
	}
	
	return;
}

int OnReceivingSocket( struct IbmsEnv *p_env , struct AcceptedSession *p_accepted_session )
{
	struct epoll_event	event ;
	
	int			nret = 0 ;
	
	if(	p_accepted_session->role == ACCEPTEDSESSION_ROLE_UNKNOWN_IDENTITY
		||
		p_accepted_session->role == ACCEPTEDSESSION_ROLE_IBMS
		||
		(
			p_accepted_session->role == ACCEPTEDSESSION_ROLE_IBMA
			&&
			(
				p_accepted_session->do_what == ACCEPTEDSESSION_DO_FETCH_CONFIG
				||
				p_accepted_session->do_what == ACCEPTEDSESSION_DO_KEEP_SILENT
			)
		)
		||
		p_accepted_session->role == ACCEPTEDSESSION_ROLE_IBAS
	)
	{
		nret = ReceiveHttpRequestNonblock( p_accepted_session->netaddr.sock , NULL , p_accepted_session->http ) ;
		if( nret == FASTERHTTP_INFO_NEED_MORE_HTTP_BUFFER )
		{
			DEBUGLOGSG( "ReceiveHttpRequestNonblock[%d] return FASTERHTTP_INFO_NEED_MORE_HTTP_BUFFER" , p_accepted_session->netaddr.sock );
			return 0;
		}
		else if( nret == FASTERHTTP_INFO_TCP_CLOSE )
		{
			WARNLOGSG( "ReceiveHttpRequestNonblock[%d] return ERROR[%d]" , p_accepted_session->netaddr.sock , nret );
			return 1;
		}
		else if( nret )
		{
			ERRORLOGSG( "ReceiveHttpRequestNonblock[%d] return ERROR[%d]" , p_accepted_session->netaddr.sock , nret );
			return 1;
		}
		else
		{
			DEBUGLOGSG( "ReceiveHttpRequestNonblock[%d] return DONE" , p_accepted_session->netaddr.sock );
			
			if( p_accepted_session->role == ACCEPTEDSESSION_ROLE_UNKNOWN_IDENTITY )
			{
				nret = OnProcess( p_env , p_accepted_session ) ;
				if( nret != HTTP_OK )
				{
					nret = FormatHttpResponseStartLine( nret , p_accepted_session->http , 1 , NULL ) ;
					if( nret )
					{
						ERRORLOGSG( "FormatHttpResponseStartLine failed[%d]" , nret );
						return 1;
					}
				}
				
				memset( & event , 0x00 , sizeof(struct epoll_event) );
				event.events = EPOLLOUT | EPOLLERR ;
				event.data.ptr = p_accepted_session ;
				nret = epoll_ctl( p_env->epoll_fd , EPOLL_CTL_MOD , p_accepted_session->netaddr.sock , & event ) ;
				if( nret == -1 )
				{
					ERRORLOGSG( "epoll_ctl[%d] modify[%d] failed , errno[%d]" , p_env->epoll_fd , p_accepted_session->netaddr.sock , errno );
					return 1;
				}
				else
				{
					DEBUGLOGSG( "epoll_ctl[%d] modify[%d] ok" , p_env->epoll_fd , p_accepted_session->netaddr.sock );
				}
			}
			else if( p_accepted_session->role == ACCEPTEDSESSION_ROLE_IBMS )
			{
				nret = OnProcess( p_env , p_accepted_session ) ;
				if( nret != HTTP_OK )
				{
					nret = FormatHttpResponseStartLine( nret , p_accepted_session->http , 1 , NULL ) ;
					if( nret )
					{
						ERRORLOGSG( "FormatHttpResponseStartLine failed[%d]" , nret );
						return 1;
					}
				}
				
				memset( & event , 0x00 , sizeof(struct epoll_event) );
				event.events = EPOLLOUT | EPOLLERR ;
				event.data.ptr = p_accepted_session ;
				nret = epoll_ctl( p_env->epoll_fd , EPOLL_CTL_MOD , p_accepted_session->netaddr.sock , & event ) ;
				if( nret == -1 )
				{
					ERRORLOGSG( "epoll_ctl[%d] modify[%d] failed , errno[%d]" , p_env->epoll_fd , p_accepted_session->netaddr.sock , errno );
					return 1;
				}
				else
				{
					DEBUGLOGSG( "epoll_ctl[%d] modify[%d] ok" , p_env->epoll_fd , p_accepted_session->netaddr.sock );
				}
			}
			else if( p_accepted_session->role == ACCEPTEDSESSION_ROLE_IBMA )
			{
				nret = OnProcess( p_env , p_accepted_session ) ;
				if( nret != HTTP_OK )
				{
					nret = FormatHttpResponseStartLine( nret , p_accepted_session->http , 1 , NULL ) ;
					if( nret )
					{
						ERRORLOGSG( "FormatHttpResponseStartLine failed[%d]" , nret );
						return 1;
					}
				}
				
				memset( & event , 0x00 , sizeof(struct epoll_event) );
				event.events = EPOLLOUT | EPOLLERR ;
				event.data.ptr = p_accepted_session ;
				nret = epoll_ctl( p_env->epoll_fd , EPOLL_CTL_MOD , p_accepted_session->netaddr.sock , & event ) ;
				if( nret == -1 )
				{
					ERRORLOGSG( "epoll_ctl[%d] modify[%d] failed , errno[%d]" , p_env->epoll_fd , p_accepted_session->netaddr.sock , errno );
					return 1;
				}
				else
				{
					DEBUGLOGSG( "epoll_ctl[%d] modify[%d] ok" , p_env->epoll_fd , p_accepted_session->netaddr.sock );
				}
			}
			else if( p_accepted_session->role == ACCEPTEDSESSION_ROLE_IBAS )
			{
				nret = OnProcess( p_env , p_accepted_session ) ;
				if( nret != HTTP_OK )
				{
					nret = FormatHttpResponseStartLine( nret , p_accepted_session->http , 1 , NULL ) ;
					if( nret )
					{
						ERRORLOGSG( "FormatHttpResponseStartLine failed[%d]" , nret );
						return 1;
					}
				}
				
				memset( & event , 0x00 , sizeof(struct epoll_event) );
				event.events = EPOLLOUT | EPOLLERR ;
				event.data.ptr = p_accepted_session ;
				nret = epoll_ctl( p_env->epoll_fd , EPOLL_CTL_MOD , p_accepted_session->netaddr.sock , & event ) ;
				if( nret == -1 )
				{
					ERRORLOGSG( "epoll_ctl[%d] modify[%d] failed , errno[%d]" , p_env->epoll_fd , p_accepted_session->netaddr.sock , errno );
					return 1;
				}
				else
				{
					DEBUGLOGSG( "epoll_ctl[%d] modify[%d] ok" , p_env->epoll_fd , p_accepted_session->netaddr.sock );
				}
			}
			else
			{
				ERRORLOGSG( "unknow role[%d]" , p_accepted_session->role );
				return 1;
			}
		}
	}
	else if( p_accepted_session->role == ACCEPTEDSESSION_ROLE_IBMA && p_accepted_session->do_what == ACCEPTEDSESSION_DO_DOWNLOAD_CONFIG )
	{
		nret = ReceiveHttpResponseNonblock( p_accepted_session->netaddr.sock , NULL , p_accepted_session->http ) ;
		if( nret == FASTERHTTP_INFO_NEED_MORE_HTTP_BUFFER )
		{
			DEBUGLOGSG( "ReceiveHttpResponseNonblock[%d] return FASTERHTTP_INFO_NEED_MORE_HTTP_BUFFER" , p_accepted_session->netaddr.sock );
			return 0;
		}
		else if( nret )
		{
			ERRORLOGSG( "ReceiveHttpResponseNonblock[%d] return ERROR[%d]" , p_accepted_session->netaddr.sock , nret );
			return 1;
		}
		else
		{
			DEBUGLOGSG( "ReceiveHttpResponseNonblock[%d] return DONE" , p_accepted_session->netaddr.sock );
			
			nret = ExtractMessageFromHttpBuffer( p_accepted_session->http , GetHttpResponseBuffer(p_accepted_session->http) , p_accepted_session->http_secure_env , NULL , NULL ) ;
			if( nret )
			{
				ERRORLOGSG( "ExtractMessageFromHttpBuffer failed[%d]" , nret );
				return 1;
			}
			
			{
			char		*STATUS_CODE = NULL ;
			int		STATUS_CODE_LEN ;
			
			STATUS_CODE = GetHttpHeaderPtr_STATUSCODE( p_accepted_session->http , & STATUS_CODE_LEN );
			
			NOTICELOGSG( "[%s][%s:%d] [POST " IBP_URI_ALIVE_NOTICE " HTTP/1.0] -> [%s][%s:%d] [%.*s]"
					, p_accepted_session->node.node , p_accepted_session->netaddr.remote_ip , p_accepted_session->netaddr.remote_port
					, "ibms" , p_env->listen_session.netaddr.ip , p_env->listen_session.netaddr.port
					, STATUS_CODE_LEN , STATUS_CODE );
			}
			
			SetHttpTimeout( p_accepted_session->http , -1 );
			ResetHttpEnv( p_accepted_session->http ) ;
			ResetHttpSecureEnv( p_accepted_session->http_secure_env );
			
			p_accepted_session->do_what = ACCEPTEDSESSION_DO_KEEP_SILENT ;
			
			memset( & event , 0x00 , sizeof(struct epoll_event) );
			event.events = EPOLLIN | EPOLLERR ;
			event.data.ptr = p_accepted_session ;
			nret = epoll_ctl( p_env->epoll_fd , EPOLL_CTL_MOD , p_accepted_session->netaddr.sock , & event ) ;
			if( nret == -1 )
			{
				ERRORLOGSG( "epoll_ctl[%d] modify[%d] failed , errno[%d]" , p_env->epoll_fd , p_accepted_session->netaddr.sock , errno );
				return 1;
			}
			else
			{
				DEBUGLOGSG( "epoll_ctl[%d] modify[%d] ok" , p_env->epoll_fd , p_accepted_session->netaddr.sock );
			}
		}
	}
	
	return 0;
}

int OnSendingSocket( struct IbmsEnv *p_env , struct AcceptedSession *p_accepted_session )
{
	struct epoll_event	event ;
	
	int			nret = 0 ;
	
	if(	p_accepted_session->role == ACCEPTEDSESSION_ROLE_UNKNOWN_IDENTITY
		||
		p_accepted_session->role == ACCEPTEDSESSION_ROLE_IBMS
		||
		(
			p_accepted_session->role == ACCEPTEDSESSION_ROLE_IBMA
			&&
			(
				p_accepted_session->do_what == ACCEPTEDSESSION_DO_FETCH_CONFIG
				||
				p_accepted_session->do_what == ACCEPTEDSESSION_DO_KEEP_SILENT
			)
		)
		||
		p_accepted_session->role == ACCEPTEDSESSION_ROLE_IBAS
	)
	{
		nret = SendHttpResponseNonblock( p_accepted_session->netaddr.sock , NULL , p_accepted_session->http ) ;
		if( nret == FASTERHTTP_INFO_TCP_SEND_WOULDBLOCK )
		{
			DEBUGLOGSG( "SendHttpResponseNonblock[%d] return FASTERHTTP_INFO_TCP_SEND_WOULDBLOCK" , p_accepted_session->netaddr.sock );
			return 0;
		}
		else if( nret )
		{
			ERRORLOGSG( "SendHttpResponseNonblock[%d] return ERROR[%d]" , p_accepted_session->netaddr.sock , nret );
			return 1;
		}
		else
		{
			DEBUGLOGSG( "SendHttpResponseNonblock[%d] return DONE" , p_accepted_session->netaddr.sock );
			
			{
			char		*METHOD = NULL ;
			int		METHOD_LEN ;
			char		*URI = NULL ;
			int		URI_LEN ;
			char		*VERSION = NULL ;
			int		VERSION_LEN ;
			char		*STATUS_CODE = NULL ;
			int		STATUS_CODE_LEN ;
			
			METHOD = GetHttpHeaderPtr_METHOD( p_accepted_session->http , & METHOD_LEN );
			URI = GetHttpHeaderPtr_URI( p_accepted_session->http , & URI_LEN );
			VERSION = GetHttpHeaderPtr_VERSION( p_accepted_session->http , & VERSION_LEN );
			STATUS_CODE = GetHttpHeaderPtr_STATUSCODE( p_accepted_session->http , & STATUS_CODE_LEN );
			
			NOTICELOGSG( "[%s][%s:%d] -> [%s][%s:%d] [%.*s %.*s %.*s] [%.*s]"
					, p_accepted_session->node.node , p_accepted_session->netaddr.ip , p_accepted_session->netaddr.port
					, "ibms" , p_env->listen_session.netaddr.ip , p_env->listen_session.netaddr.port
					, METHOD_LEN , METHOD
					, URI_LEN , URI
					, VERSION_LEN , VERSION
					, STATUS_CODE_LEN , STATUS_CODE );
			}
			
			if( p_accepted_session->role == ACCEPTEDSESSION_ROLE_IBMA || p_accepted_session->role == ACCEPTEDSESSION_ROLE_IBAS )
			{
				if( STRCMP( p_accepted_session->node.node , == , "" ) )
				{
					return 1;
				}
			}
			
			if( ! CheckHttpKeepAlive(p_accepted_session->http) )
			{
				return 1;
			}
			
			SetHttpTimeout( p_accepted_session->http , -1 );
			ResetHttpEnv( p_accepted_session->http ) ;
			ResetHttpSecureEnv( p_accepted_session->http_secure_env );
			
			if( p_accepted_session->role == ACCEPTEDSESSION_ROLE_IBMA && p_accepted_session->do_what == ACCEPTEDSESSION_DO_FETCH_CONFIG )
			{
				p_accepted_session->do_what = ACCEPTEDSESSION_DO_KEEP_SILENT ;
				DEBUGLOGSG( "set p_accepted_session->do_what ACCEPTEDSESSION_DO_KEEP_SILENT" );
			}
			
			memset( & event , 0x00 , sizeof(struct epoll_event) );
			event.events = EPOLLIN | EPOLLERR ;
			event.data.ptr = p_accepted_session ;
			nret = epoll_ctl( p_env->epoll_fd , EPOLL_CTL_MOD , p_accepted_session->netaddr.sock , & event ) ;
			if( nret == -1 )
			{
				ERRORLOGSG( "epoll_ctl[%d] modify[%d] failed , errno[%d]" , p_env->epoll_fd , p_accepted_session->netaddr.sock , errno );
				return 1;
			}
			else
			{
				DEBUGLOGSG( "epoll_ctl[%d] modify[%d] ok" , p_env->epoll_fd , p_accepted_session->netaddr.sock );
			}
		}
	}
	else if( p_accepted_session->role == ACCEPTEDSESSION_ROLE_IBMA && p_accepted_session->do_what == ACCEPTEDSESSION_DO_DOWNLOAD_CONFIG )
	{
		nret = SendHttpRequestNonblock( p_accepted_session->netaddr.sock , NULL , p_accepted_session->http ) ;
		if( nret == FASTERHTTP_INFO_TCP_SEND_WOULDBLOCK )
		{
			DEBUGLOGSG( "SendHttpRequestNonblock[%d] return FASTERHTTP_INFO_NEED_MORE_HTTP_BUFFER" , p_accepted_session->netaddr.sock );
			return 0;
		}
		else if( nret )
		{
			ERRORLOGSG( "SendHttpRequestNonblock[%d] return ERROR[%d]" , p_accepted_session->netaddr.sock , nret );
			return 1;
		}
		else
		{
			DEBUGLOGSG( "SendHttpRequestNonblock[%d] return DONE" , p_accepted_session->netaddr.sock );
			
			SetHttpTimeout( p_accepted_session->http , -1 );
			ResetHttpEnv( p_accepted_session->http ) ;
			ResetHttpSecureEnv( p_accepted_session->http_secure_env );
			
			memset( & event , 0x00 , sizeof(struct epoll_event) );
			event.events = EPOLLIN | EPOLLERR ;
			event.data.ptr = p_accepted_session ;
			nret = epoll_ctl( p_env->epoll_fd , EPOLL_CTL_MOD , p_accepted_session->netaddr.sock , & event ) ;
			if( nret == -1 )
			{
				ERRORLOGSG( "epoll_ctl[%d] modify[%d] failed , errno[%d]" , p_env->epoll_fd , p_accepted_session->netaddr.sock , errno );
				return 1;
			}
			else
			{
				DEBUGLOGSG( "epoll_ctl[%d] modify[%d] ok" , p_env->epoll_fd , p_accepted_session->netaddr.sock );
			}
		}
	}
	
	return 0;
}

